package com.acdc.wechat.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.entity.StringEntity;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.acdc.business.domain.RechargeRecord;
import com.acdc.business.service.IRechargeRecordService;
import com.acdc.utils.SignUtils;
import com.acdc.utils.JSSDKUtils;
import com.acdc.wechat.config.WechatPayConfig;
import com.acdc.wechat.utils.WechatPayV3SignatureVerifier;
import com.acdc.wechat.utils.WechatPayDecryptUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.common.core.domain.entity.SysUser;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;


 import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class WechatPayService {

    private final ObjectMapper objectMapper = new ObjectMapper();
    
    @Autowired
    private WechatPayConfig wechatPayConfig;
    
    @Value("${wechat.pay.api-v3-key}")
    private String apiV3Key;
    
    @Value("${wechat.pay.notify-url}")
    private String notifyUrl;
    
    @Value("${wechat.pay.merchant-serial-no}")
    private String merchantSerialNo;
    
    @Value("${wechat.pay.app-secret}")
    private String appSecret;

    @Autowired
    private ISysUserService userService;

    @Autowired
    private IRechargeRecordService rechargeRecordService;

    /**
     * 统一下单接口，获取支付参数
     */
    public Map<String, String> createOrder(int totalAmount, String openid, String meterNo) throws Exception {
        SysUser user = userService.selectUserByOpenId(openid);
        if (user == null) {
            throw new RuntimeException("用户不存在，openId: " + openid);
        }
        log.info("创建支付订单，用户: {}, openId: {}, 金额: {}", user.getNickName(), openid, totalAmount);
        
        // 生成订单号, yyyyMMddHHmmss+userId+随机数（4位数字，不足4位补0）
        String outTradeNo = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + user.getUserId() + String.format("%04d", (int)(Math.random() * 10000));
        String description = "用户" + (user.getNickName() != null ? user.getNickName() : "未知") + "充值" + totalAmount/100.0f + "元";

        // 构建请求参数
        Map<String, Object> params = new HashMap<>();
        params.put("appid", wechatPayConfig.getAppid());
        params.put("mchid", wechatPayConfig.getMerchantId());
        params.put("description", description);
        params.put("out_trade_no", outTradeNo);
        params.put("notify_url", notifyUrl);
        
        Map<String, Object> amount = new HashMap<>();
        amount.put("total", totalAmount); // 单位：分
        amount.put("currency", "CNY");
        params.put("amount", amount);
        
        Map<String, Object> payer = new HashMap<>();
        payer.put("openid", openid);
        params.put("payer", payer);
        
        // 创建HTTP请求
        HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi");
        httpPost.addHeader("Content-Type", "application/json");
        httpPost.addHeader("Accept", "application/json");
        
        // 生成请求体
        String requestBody = objectMapper.writeValueAsString(params);
        httpPost.setEntity(new StringEntity(requestBody, StandardCharsets.UTF_8));
        
        // 执行请求
        try (CloseableHttpResponse response = wechatPayConfig.wechatPayClient().execute(httpPost)) {
            String bodyAsString = EntityUtils.toString(response.getEntity());
            log.info("创建订单返回数据: {}", bodyAsString);
            
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode != 200) {
                throw new RuntimeException("创建订单失败，HTTP状态码: " + statusCode + ", 响应: " + bodyAsString);
            }
            
            @SuppressWarnings("unchecked")
            Map<String, Object> resultMap = objectMapper.readValue(bodyAsString, Map.class);
            if (resultMap.get("prepay_id") == null) {
                throw new RuntimeException("创建订单失败: " + resultMap.get("message"));
            }
            // 创建充值订单
            RechargeRecord rechargeRecord = new RechargeRecord();
            rechargeRecord.setUserId(user.getUserId());
            rechargeRecord.setOrderId(outTradeNo);
            rechargeRecord.setAmount(totalAmount/100.0f);
            rechargeRecord.setRechargeType(0L);
            rechargeRecord.setStatus(0L);
            rechargeRecord.setTransactionId((String) resultMap.get("prepay_id"));
            rechargeRecord.setRemark("微信支付");
            rechargeRecord.setCreatedAt(new Date());
            rechargeRecord.setUpdatedAt(new Date());
            rechargeRecord.setMeterNo(meterNo);
            rechargeRecordService.insertRechargeRecord(rechargeRecord);
            // 生成小程序调起支付的参数
            String prepayId = (String) resultMap.get("prepay_id");
            Map<String, String> payParams = generatePaySign(prepayId);
            payParams.put("outTradeNo", outTradeNo);
            return payParams;
        } catch (Exception e) {
            log.error("创建订单失败: ", e);
            throw new RuntimeException("创建订单失败: " + e.getMessage());
        }
    }
    
    /**
     * 生成小程序调起支付的签名
     */
    private Map<String, String> generatePaySign(String prepayId) {
        String appId = wechatPayConfig.getAppid();
        String timeStamp = String.valueOf(System.currentTimeMillis() / 1000);
        String nonceStr = UUID.randomUUID().toString().replaceAll("-", "");
        String packageStr = "prepay_id=" + prepayId;
        String signType = "RSA";
        
        log.info("生成支付签名参数 - appId: {}, timeStamp: {}, nonceStr: {}, package: {}", 
                appId, timeStamp, nonceStr, packageStr);
        
        // 签名 - 使用修复后的签名方法
        String sign = SignUtils.sign(wechatPayConfig.getMerchantId(), appId, timeStamp, nonceStr, packageStr);
        
        log.info("生成的签名: {}", sign);
        
        // 构建返回参数 - 注意字段名要与前端一致
        Map<String, String> payParams = new HashMap<>();
        payParams.put("appId", appId);
        payParams.put("timeStamp", timeStamp);
        payParams.put("nonceStr", nonceStr);
        payParams.put("package", packageStr);
        payParams.put("signType", signType);
        payParams.put("paySign", sign);
        
        log.info("返回的支付参数: {}", payParams);
        
        return payParams;
    }
    
    /**
     * 处理支付结果通知
     */
    public String handlePayNotify(String notifyData, String nonce, String timestamp, String signature) 
            throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, 
            InvalidKeyException, BadPaddingException, IllegalBlockSizeException, GeneralSecurityException, 
            JsonProcessingException, JsonMappingException {
        
        log.info("收到支付通知 - nonce: {}, timestamp: {}, signature: {}", nonce, timestamp, signature);
        log.info("通知数据: {}", notifyData);
        
        try {
            // 验证签名 - 使用微信支付V3通知签名验证
            // 构建签名验证所需的参数
            String method = "POST";
            String urlPath = "/wechat/pay/notify";
            String nonceStr = nonce;
            String body = notifyData;
            
            // 使用专门的V3签名验证工具
            boolean verifyResult = WechatPayV3SignatureVerifier.verify(method, urlPath, timestamp, nonceStr, body, signature);
            if (!verifyResult) {
                log.error("签名验证失败 - 签名不匹配");
                
                // 尝试使用简化验证
                log.info("尝试使用简化签名验证");
                boolean simpleVerifyResult = WechatPayV3SignatureVerifier.verifySimple(method, urlPath, timestamp, nonceStr, body, signature);
                
                if (!simpleVerifyResult) {
                    log.error("简化签名验证也失败");
                    throw new RuntimeException("签名验证失败");
                } else {
                    log.warn("简化签名验证通过，但建议配置完整的证书验证");
                }
            } else {
                log.info("签名验证成功");
            }
            
        } catch (Exception e) {
            log.error("签名验证异常", e);
            throw new RuntimeException("签名验证失败: " + e.getMessage());
        }
        
        // 解析通知数据
        @SuppressWarnings("unchecked")
        Map<String, Object> resultMap = objectMapper.readValue(notifyData, Map.class);
        
        // 获取加密的资源数据
        @SuppressWarnings("unchecked")
        Map<String, Object> resource = (Map<String, Object>) resultMap.get("resource");
        
        if (resource == null) {
            log.error("通知数据中缺少resource字段");
            throw new RuntimeException("通知数据格式错误：缺少resource字段");
        }
        
        String ciphertext = (String) resource.get("ciphertext");
        String associatedData = (String) resource.get("associated_data");
        String nonceStr = (String) resource.get("nonce");
        
        // 验证解密参数
        if (ciphertext == null || ciphertext.trim().isEmpty()) {
            log.error("ciphertext为空或null");
            throw new RuntimeException("解密参数错误：ciphertext为空");
        }
        
        if (nonceStr == null || nonceStr.trim().isEmpty()) {
            log.error("nonce为空或null");
            throw new RuntimeException("解密参数错误：nonce为空");
        }
        
        // associated_data可以为空，但需要处理
        if (associatedData == null) {
            associatedData = "";
        }
        
        log.info("加密数据 - ciphertext长度: {}, associatedData: '{}', nonce: '{}'", 
                ciphertext.length(), associatedData, nonceStr);
        
        // 解密通知数据
        String decryptData;
        try {
            // 使用专门的解密工具
            decryptData = WechatPayDecryptUtil.decryptWithFallback(ciphertext, associatedData, nonceStr, apiV3Key);
            log.info("解密成功，解密后数据: {}", decryptData);
            
        } catch (Exception e) {
            log.error("解密失败 - ciphertext: {}, associatedData: '{}', nonce: '{}', apiV3Key长度: {}", 
                    ciphertext, associatedData, nonceStr, apiV3Key.length());
            log.error("解密异常详情", e);
            throw new RuntimeException("解密通知数据失败: " + e.getMessage());
        }
        
        // 解析解密后的数据
        @SuppressWarnings("unchecked")
        Map<String, Object> transaction = objectMapper.readValue(decryptData, Map.class);
        
        // 处理订单逻辑（更新订单状态等）
        String outTradeNo = (String) transaction.get("out_trade_no");
        String transactionId = (String) transaction.get("transaction_id");
        String tradeState = (String) transaction.get("trade_state");
        
        log.info("订单信息 - outTradeNo: {}, transactionId: {}, tradeState: {}", 
                outTradeNo, transactionId, tradeState);
        
        if ("SUCCESS".equals(tradeState)) {
            // 更新订单状态
            RechargeRecord query = new RechargeRecord();
            query.setOrderId(outTradeNo);
            List<RechargeRecord> rechargeRecordList = rechargeRecordService.selectRechargeRecordList(query);
            if (rechargeRecordList.size() > 0) {
                RechargeRecord rechargeRecord = rechargeRecordList.get(0);
                if (rechargeRecord.getStatus() == 1L) {
                    return "{\"code\":\"SUCCESS\",\"message\":\"支付已处理\"}";
                }
                rechargeRecord.setStatus(1L);
                rechargeRecord.setUpdatedAt(new Date());
                rechargeRecord.setTransactionId(transactionId);
                @SuppressWarnings("unchecked")
                Map<String, Object> amount = (Map<String, Object>) transaction.get("amount");
                rechargeRecord.setAmount(((Number) amount.get("total")).intValue() / 100.0f);
                rechargeRecordService.updateRechargeRecord(rechargeRecord);
                // 更新订单状态
                SysUser user = userService.selectUserById(rechargeRecord.getUserId());
                user.setBalance(user.getBalance() + rechargeRecord.getAmount());
                userService.updateUser(user);
                
                log.info("支付成功 - 订单: {}, 用户: {}, 金额: {}", 
                        outTradeNo, user.getUserId(), rechargeRecord.getAmount());
            }
            
        } else {
            // 更新订单状态
            RechargeRecord query = new RechargeRecord();
            query.setOrderId(outTradeNo);
            List<RechargeRecord> rechargeRecordList = rechargeRecordService.selectRechargeRecordList(query);
            if (rechargeRecordList.size() > 0) {
                RechargeRecord rechargeRecord = rechargeRecordList.get(0);
                rechargeRecord.setStatus(2L);
                rechargeRecord.setUpdatedAt(new Date());
                // 从微信获取失败原因
                String failReason = (String) transaction.get("fail_reason");
                if (failReason != null) {
                    rechargeRecord.setRemark(failReason);
                } else {
                    rechargeRecord.setRemark("微信支付失败");
                }
                rechargeRecordService.updateRechargeRecord(rechargeRecord);
                
                log.info("支付失败 - 订单: {}, 原因: {}", outTradeNo, failReason);
            }
        }
        
        // 返回成功响应
        return "{\"code\":\"SUCCESS\",\"message\":\"成功\"}";
    }
    
    /**
     * 获取微信JSSDK配置
     * @param url 当前页面URL
     * @return JSSDK配置参数
     */
    public Map<String, String> getJSSDKConfig(String url) throws Exception {
        try {
            // 获取access_token
            String accessToken = getAccessToken();
            
            // 获取jsapi_ticket
            String jsapiTicket = getJsapiTicket(accessToken);
            
            // 生成JSSDK配置参数
            String nonceStr = JSSDKUtils.generateNonceStr();
            String timestamp = JSSDKUtils.generateTimestamp();
            String signature = JSSDKUtils.generateJSSDKSignature(jsapiTicket, nonceStr, timestamp, url);
            
            Map<String, String> config = new HashMap<>();
            config.put("appId", wechatPayConfig.getAppid());
            config.put("timestamp", timestamp);
            config.put("nonceStr", nonceStr);
            config.put("signature", signature);
            
            return config;
        } catch (Exception e) {
            log.error("获取JSSDK配置失败: ", e);
            
            // 如果是IP白名单错误，提供更友好的错误信息
            if (e.getMessage() != null && e.getMessage().contains("40164")) {
                throw new RuntimeException("微信JSSDK配置失败：服务器IP地址不在微信公众平台白名单中。请联系管理员将服务器IP添加到微信白名单中。");
            }
            
            throw new RuntimeException("获取JSSDK配置失败: " + e.getMessage());
        }
    }
    
    /**
     * 获取微信access_token
     */
    private String getAccessToken() throws Exception {
        String url = String.format(
            "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s",
            wechatPayConfig.getAppid(), appSecret
        );
        
        try (CloseableHttpResponse response = wechatPayConfig.wechatPayClient().execute(new HttpGet(url))) {
            String bodyAsString = EntityUtils.toString(response.getEntity());
            log.info("获取access_token返回数据: {}", bodyAsString);
            
            @SuppressWarnings("unchecked")
            Map<String, Object> resultMap = objectMapper.readValue(bodyAsString, Map.class);
            
            if (resultMap.get("access_token") == null) {
                String errmsg = (String) resultMap.get("errmsg");
                Integer errcode = (Integer) resultMap.get("errcode");
                
                // 特殊处理IP白名单错误
                if (errcode != null && errcode == 40164) {
                    String errorDetail = "IP地址不在微信公众平台白名单中。";
                    errorDetail += "请登录微信公众平台，进入'设置与开发' -> '基本配置' -> 'IP白名单'，";
                    errorDetail += "添加服务器IP地址: " + getServerIP() + "。";
                    errorDetail += "或者联系管理员将当前服务器IP添加到微信白名单中。";
                    throw new RuntimeException("获取access_token失败: " + errmsg + "。解决方案: " + errorDetail);
                }
                
                throw new RuntimeException("获取access_token失败: " + errmsg + " (错误码: " + errcode + ")");
            }
            
            return (String) resultMap.get("access_token");
        }
    }
    
    /**
     * 获取服务器IP地址
     */
    private String getServerIP() {
        try {
            // 尝试获取本机IP地址
            java.net.InetAddress localHost = java.net.InetAddress.getLocalHost();
            return localHost.getHostAddress();
        } catch (Exception e) {
            return "未知IP地址";
        }
    }
    
    /**
     * 获取微信jsapi_ticket
     */
    private String getJsapiTicket(String accessToken) throws Exception {
        String url = String.format(
            "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi",
            accessToken
        );
        
        try (CloseableHttpResponse response = wechatPayConfig.wechatPayClient().execute(new HttpGet(url))) {
            String bodyAsString = EntityUtils.toString(response.getEntity());
            log.info("获取jsapi_ticket返回数据: {}", bodyAsString);
            
            @SuppressWarnings("unchecked")
            Map<String, Object> resultMap = objectMapper.readValue(bodyAsString, Map.class);
            
            if (resultMap.get("ticket") == null) {
                throw new RuntimeException("获取jsapi_ticket失败: " + resultMap.get("errmsg"));
            }
            
            return (String) resultMap.get("ticket");
        }
    }

}

